///////////////////////////////////////////////////////////////////////////////
//
// main.cpp
//
///////////////////////////////////////////////////////////////////////////////
//
// Author:            Jan Maes
// Created:           Sunday, June 15, 2008
// Responsibilities:  Unit testing of HandleFactory::HandleFactory and 
//                    HandleFactory::Handle
//          
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
// Includes
///////////////////////////////////////////////////////////////////////////////

#include "FixtureTestHandle.h"
#include "MyObjectAsAutoPtr.h"
#include "MyObjectAsHandle.h"
#include "MyObjectAsIntrusivePtr.h"
#include "MyObjectAsSharedPtr.h"
#include "MyObjectWithManyParameters.h"

#include <Unittest++/src/UnitTest++.h>

#include <boost/smart_ptr.hpp>

#include <memory>

///////////////////////////////////////////////////////////////////////////////
// UnitTests
///////////////////////////////////////////////////////////////////////////////

TEST(CreateMyObjectAsSharedPtrWithDefaultConstructor)
  {
  MyObjectAsSharedPtr::THandleType p_object = MyObjectAsSharedPtr::Create();

  CHECK(p_object.get() != 0);
  }

///////////////////////////////////////////////////////////////////////////////

TEST(CreateMyObjectAsSharedPtrWithOneParameterConstructor)
  {
  MyObjectAsSharedPtr::THandleType p_object = MyObjectAsSharedPtr::Create(5.0);

  CHECK(p_object.get() != 0);
  CHECK_EQUAL(p_object->GetDouble(), 5.0);
  }

///////////////////////////////////////////////////////////////////////////////

TEST(CreateMyObjectAsAutoPtrWithDefaultConstructor)
  {
  MyObjectAsAutoPtr::THandleType p_object = MyObjectAsAutoPtr::Create();

  CHECK(p_object.get() != 0);
  }

///////////////////////////////////////////////////////////////////////////////

TEST(CreateMyObjectAsAutoPtrWithOneParameterConstructor)
  {
  MyObjectAsAutoPtr::THandleType p_object = MyObjectAsAutoPtr::Create(234324.0);

  CHECK(p_object.get() != 0);
  CHECK_EQUAL(p_object->GetDouble(), 234324.0);
  }

///////////////////////////////////////////////////////////////////////////////

TEST(CreateMyObjectAsHandleWithDefaultConstructor)
  {
  MyObjectAsHandle::THandleType p_object = MyObjectAsHandle::Create();

  CHECK(p_object.GetInternalObject() != 0);
  }

///////////////////////////////////////////////////////////////////////////////

TEST(CreateMyObjectAsHandleWithOneParameterConstructor)
  {
  MyObjectAsHandle::THandleType p_object = MyObjectAsHandle::Create(234324.0);

  CHECK(p_object.GetInternalObject() != 0);
  CHECK_EQUAL(p_object->GetDouble(), 234324.0);
  }

///////////////////////////////////////////////////////////////////////////////

TEST(CreateMyObjectAsIntrusivePtrWithDefaultConstructor)
  {
  MyObjectAsIntrusivePtr::THandleType p_object = MyObjectAsIntrusivePtr::Create();

  CHECK(p_object.get() != 0);
  }

///////////////////////////////////////////////////////////////////////////////

TEST(CreateMyObjectAsIntrusivePtrWithOneParameterConstructor)
  {
  MyObjectAsIntrusivePtr::THandleType p_object = MyObjectAsIntrusivePtr::Create(234324.0);

  CHECK(p_object.get() != 0);
  CHECK_EQUAL(p_object->GetDouble(), 234324.0);
  }

///////////////////////////////////////////////////////////////////////////////

TEST(CreateMyObjectWithManyParameters)
  {
  MyObjectWithManyParameters::THandleType p_object_1 = MyObjectWithManyParameters::Create();

  CHECK(p_object_1.GetInternalObject() != 0);
  CHECK_EQUAL(p_object_1->m_double, 0.0);

  MyObjectWithManyParameters::THandleType p_object_2 = MyObjectWithManyParameters::Create(5.0, SomeEmptyClass(), 3, "Jan");

  CHECK(p_object_2.GetInternalObject() != 0);
  CHECK_EQUAL(p_object_2->m_double, 5.0);
  CHECK_EQUAL(p_object_2->m_int, 3);
  CHECK_EQUAL(p_object_2->m_string, "Jan");

  MyObjectWithManyParameters::THandleTypeConst p_object_3 = MyObjectWithManyParameters::CreateConst();

  CHECK(p_object_3.GetInternalObject() != 0);
  CHECK_EQUAL(p_object_3->m_double, 0.0);

  MyObjectWithManyParameters::THandleTypeConst p_object_4 = MyObjectWithManyParameters::CreateConst(5.0, SomeEmptyClass(), 3, "Jan");

  CHECK(p_object_4.GetInternalObject() != 0);
  CHECK_EQUAL(p_object_4->m_double, 5.0);
  CHECK_EQUAL(p_object_4->m_int, 3);
  CHECK_EQUAL(p_object_4->m_string, "Jan");
  }

///////////////////////////////////////////////////////////////////////////////

TEST(ConstCreate)
  {
  MyObjectAsHandle::THandleTypeConst p_object_1 = MyObjectAsHandle::CreateConst();
  CHECK(p_object_1.GetInternalObject() != 0);
  //MyObjectAsAutoPtr::THandleTypeConst p_object_2 = MyObjectAsAutoPtr::CreateConst();
  //CHECK(p_object_2.get() != 0);
  MyObjectAsSharedPtr::THandleTypeConst p_object_3 = MyObjectAsSharedPtr::CreateConst();
  CHECK(p_object_3.get() != 0);
  }

///////////////////////////////////////////////////////////////////////////////

TEST(InvalidHandleTest)
  {
  MyObjectAsHandle::THandleType p_object_1;
  MyObjectAsHandle::THandleType p_object_2;
  CHECK(!p_object_1.IsValid());
  CHECK(!p_object_2.IsValid());
  CHECK(p_object_1.IsUnique());
  CHECK(p_object_2.IsUnique());
  p_object_1 = p_object_2;
  CHECK(!p_object_1.IsValid());
  CHECK(!p_object_2.IsValid());
  CHECK(!p_object_1.IsUnique());
  CHECK(!p_object_2.IsUnique());  
  }

///////////////////////////////////////////////////////////////////////////////

TEST(InvalidHandleTestDestruction)
  {
  MyObjectAsHandle::THandleType p_object_1;
    {
    MyObjectAsHandle::THandleType p_object_2;
    CHECK(!p_object_1.IsValid());
    CHECK(!p_object_2.IsValid());
    CHECK(p_object_1.IsUnique());
    CHECK(p_object_2.IsUnique());
    p_object_1 = p_object_2;
    CHECK(!p_object_1.IsValid());
    CHECK(!p_object_2.IsValid());
    CHECK(!p_object_1.IsUnique());
    CHECK(!p_object_2.IsUnique());  
    }
  CHECK(!p_object_1.IsValid());
  CHECK(p_object_1.IsUnique());
  }

///////////////////////////////////////////////////////////////////////////////

TEST_FIXTURE(FixtureTestHandle, TestHandleClassIsUnique)
  {
  CHECK(mp_object_1.IsUnique());
  CHECK(mp_object_2.IsUnique());
  CHECK(mp_object_3.IsUnique());
  }

///////////////////////////////////////////////////////////////////////////////

TEST_FIXTURE(FixtureTestHandle, TestHandleClassIsValid)
  {
  CHECK(mp_object_1.IsValid());
  CHECK(mp_object_2.IsValid());
  CHECK(!mp_object_3.IsValid());
  }

///////////////////////////////////////////////////////////////////////////////

TEST_FIXTURE(FixtureTestHandle, TestHandleClassAssignment)
  {
  CHECK(!mp_object_3.IsValid());
  CHECK(mp_object_3.IsUnique());
  mp_object_3 = MyObjectAsHandle::Create(5.0);
  CHECK(mp_object_3.IsValid());
  CHECK(mp_object_3.IsUnique());
  }

///////////////////////////////////////////////////////////////////////////////

TEST_FIXTURE(FixtureTestHandle, TestHandleClassCheckRefCounting)
  {
  CHECK(!mp_object_3.IsValid());
  CHECK(mp_object_3.IsUnique());
  CHECK_EQUAL(mp_object_3.GetRefCount(), static_cast<unsigned long>(1));
  mp_object_3 = MyObjectAsHandle::Create(5.0);
  CHECK_EQUAL(mp_object_3.GetRefCount(), static_cast<unsigned long>(1));
  mp_object_1 = mp_object_3;
  CHECK_EQUAL(mp_object_1.GetRefCount(), static_cast<unsigned long>(2));
  CHECK_EQUAL(mp_object_3.GetRefCount(), static_cast<unsigned long>(2));
  }

///////////////////////////////////////////////////////////////////////////////

TEST_FIXTURE(FixtureTestHandle, TestHandleClassAssignmentAndRefCount)
  {
  CHECK(mp_object_1.IsValid());
  CHECK(mp_object_2.IsValid());
  CHECK(!mp_object_3.IsValid());
  CHECK_EQUAL(mp_object_1.GetRefCount(), static_cast<unsigned long>(1));
  CHECK_EQUAL(mp_object_2.GetRefCount(), static_cast<unsigned long>(1));
  CHECK_EQUAL(mp_object_3.GetRefCount(), static_cast<unsigned long>(1));
  mp_object_3 = mp_object_1;
  CHECK(mp_object_1.IsValid());
  CHECK(mp_object_2.IsValid());
  CHECK(mp_object_3.IsValid());  
  CHECK_EQUAL(mp_object_1.GetRefCount(), static_cast<unsigned long>(2));
  CHECK_EQUAL(mp_object_2.GetRefCount(), static_cast<unsigned long>(1));
  CHECK_EQUAL(mp_object_3.GetRefCount(), static_cast<unsigned long>(2));
  mp_object_1 = mp_object_2;
  CHECK(mp_object_1.IsValid());
  CHECK(mp_object_2.IsValid());
  CHECK(mp_object_3.IsValid()); 
  CHECK_EQUAL(mp_object_1.GetRefCount(), static_cast<unsigned long>(2));
  CHECK_EQUAL(mp_object_2.GetRefCount(), static_cast<unsigned long>(2));
  CHECK_EQUAL(mp_object_3.GetRefCount(), static_cast<unsigned long>(1));
  mp_object_3 = mp_object_1;
  CHECK(mp_object_1.IsValid());
  CHECK(mp_object_2.IsValid());
  CHECK(mp_object_3.IsValid());  
  CHECK_EQUAL(mp_object_1.GetRefCount(), static_cast<unsigned long>(3));
  CHECK_EQUAL(mp_object_2.GetRefCount(), static_cast<unsigned long>(3));
  CHECK_EQUAL(mp_object_3.GetRefCount(), static_cast<unsigned long>(3));
  }

///////////////////////////////////////////////////////////////////////////////

TEST_FIXTURE(FixtureTestHandle, TestHandleClassCheckDestructor)
  {

    {
    MyObjectAsHandle::THandleType p_object_4;
    CHECK(mp_object_1.IsValid());
    CHECK(!p_object_4.IsValid());
    p_object_4 = mp_object_1;
    CHECK(mp_object_1.IsValid());
    CHECK(p_object_4.IsValid());
    CHECK_EQUAL(mp_object_1.GetRefCount(), static_cast<unsigned long>(2));
    CHECK_EQUAL(p_object_4.GetRefCount(), static_cast<unsigned long>(2));
    CHECK(p_object_4.GetInternalObject() != 0);
    }

  CHECK(mp_object_1.IsValid());
  CHECK(mp_object_1.IsUnique());
  CHECK(mp_object_1.GetInternalObject() != 0);
  }

///////////////////////////////////////////////////////////////////////////////

TEST_FIXTURE(FixtureTestHandle, TestHandleClassCheckEquivalence)
  {
  CHECK(mp_object_1 != mp_object_2);
  CHECK(mp_object_1 != mp_object_3);
  CHECK(mp_object_3 != mp_object_4);
  mp_object_4 = mp_object_3;
  CHECK(mp_object_3 == mp_object_4);
  mp_object_1 = mp_object_3;
  CHECK(mp_object_4 == mp_object_1);
  mp_object_1 = mp_object_2;
  CHECK(mp_object_1 == mp_object_2);
  }

///////////////////////////////////////////////////////////////////////////////

TEST_FIXTURE(FixtureTestHandle, TestHandleClassCheckSwap)
  {
  mp_object_3 = MyObjectAsHandle::Create(5.0);
  mp_object_4 = MyObjectAsHandle::Create(6.0);
  mp_object_3.Swap(mp_object_4);
  CHECK_EQUAL(mp_object_3->GetDouble(), 6.0);
  CHECK_EQUAL(mp_object_4->GetDouble(), 5.0);
  }

///////////////////////////////////////////////////////////////////////////////
// Main function
///////////////////////////////////////////////////////////////////////////////

int main()
  {
  return UnitTest::RunAllTests();
  }

///////////////////////////////////////////////////////////////////////////////